/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.dao.product;

import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.martinimix.dao.DataAccessException;
import net.martinimix.domain.product.Product;

import com.bluemartini.database.BMDatabaseManager;
import com.bluemartini.dna.BMException;
import com.bluemartini.dna.Currency;
import com.bluemartini.remotedesktop.ObjectAttribute;
import com.bluemartini.remotedesktop.ObjectAttributeArray;
import com.bluemartini.remotedesktop.ObjectPrice;
import com.bluemartini.remotedesktop.PriceList;
import com.bluemartini.remotedesktop.PriceListArray;
import com.bluemartini.remotedesktop.PriceListFolder;
import com.bluemartini.remotedesktop.util.PricingUtil;

/**
 * Provides a Blue Martini remote desktop product data access object.
 * 
 * @author Scott Rossillo
 *
 */
public class BlueMartiniRemoteDesktopProductDao implements ProductDao {
	
	private final static Log log = LogFactory.getLog(BlueMartiniRemoteDesktopProductDao.class);
	
	private String descriptionAttribute;
	private String externalProductCodeAttribute;
	private String priceListFolder;
	
	private Long descriptionAttributeId = null;

	/**
	 * FIXME: Unimplemented.
	 * @see net.martinimix.dao.product.ProductDao#findProductByCode(java.lang.String)
	 */
	public Product findProductByCode(String productCode) {
		
		throw new  UnsupportedOperationException("Method [findProductByCode] unimplemented.");
	}

	/* (non-Javadoc)
	 * @see net.martinimix.dao.product.ProductDao#findProductById(java.lang.Long)
	 */
	public Product findProductById(Long id) {
		
		Product product = new Product();
		com.bluemartini.remotedesktop.Product bmProduct;
		
		BMDatabaseManager.pushCurrentDatabase("main");
		try {
			bmProduct = com.bluemartini.remotedesktop.Product.getProductByID(id);
			
			if(bmProduct == null) {
				return null;
			}
			
			product.setId(bmProduct.getLongID());
			product.setProductCode(bmProduct.getProductCode());
			product.setExternalProductCode(bmProduct.getString(externalProductCodeAttribute));
			product.setDescription(bmProduct.getString(descriptionAttribute));
			
			if(product.getDescription() == null) {
				product.setDescription(findAttribute(bmProduct, descriptionAttribute));
			}
			
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet("main");
		}
		
		return product;
	}
	
	protected String findAttribute(com.bluemartini.remotedesktop.Product  product, String name) {
		
		ObjectAttributeArray attributes = product.getObjectAttributesForView();
		ObjectAttribute attribute;
		Long id;
		
		// attribute queries can be slow, so this shortcut is used
		if(descriptionAttributeId == null) {
			descriptionAttributeId = getAttributeId(attributes, name);
		}

		for(int i = 0; descriptionAttributeId != null && i < attributes.size(); i++) {
			id = attributes.getID(i);
			if(descriptionAttributeId.equals(id)) {
				attribute = attributes.getObjectAttribute(i);
				return attribute.getDisplayableValue();
			}
		}

		return null;
	}

	private Long getAttributeId(ObjectAttributeArray attributes, String name) {
		
		ObjectAttribute attribute;
		
		// this is quite slow
		for(int i = 0; i < attributes.size(); i++) {
			attribute = attributes.getObjectAttribute(i);
			
			if(name.equals(attribute.getAttributeName())) {
				return attribute.getAttributeID();
			}
		}
		
		return null;
	}
	
	/* (non-Javadoc)
	 * @see net.martinimix.dao.product.ProductDao#getProductPrice(java.lang.Long)
	 */
	public BigDecimal getProductPrice(Long productId) {
		
		PriceListFolder folder;
		PriceListArray priceListArray;
		PriceList priceList;
		
		ObjectPrice price;
		Currency currency;
		
		log.debug("Getting price for product [" + productId + "] form [" + priceListFolder + "]");
		
		BMDatabaseManager.pushCurrentDatabase("main");
		try {
			folder = PricingUtil.getPriceListFolderByName(priceListFolder);
			priceListArray = folder.getPriceLists();
			
			// FIXME: we're assuming the first price list is valid
			if(priceListArray == null || priceListArray.size() == 0) {
				throw new DataAccessException("No price lists found in folder [" + priceListFolder + "]");
			}
			
			priceList = priceListArray.getPriceList(0);
			price = PricingUtil.getObjectPrice(productId, priceList.getLongID());
			
			if(price != null) {
				currency = price.getPriceAmount();
				return currency.toBigDecimal();
			}
			
		} catch (BMException e) {
			throw new DataAccessException("Unable to read price lists folder [" + priceListFolder + "]", e);
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet("main");
		}
		
		return null;
	}
	
	public void setDescriptionAttribute(String descriptionAttribute) {
		this.descriptionAttribute = descriptionAttribute;
	}

	public void setExternalProductCodeAttribute(String externalProductCodeAttribute) {
		this.externalProductCodeAttribute = externalProductCodeAttribute;
	}

	public void setPriceListFolder(String priceListFolder) {
		this.priceListFolder = priceListFolder;
	}

}
